#include <stdio.h>
#include <stdarg.h>
#include "rs_config.h"
#include "ll.h"
#include "route.h"
#include "tap.h"
#include "tp_debug.h"

#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif /* min */

extern int scps_udp_port1;

extern GW_ifs gw_ifs;

static char aif_addr_string[256];
static char aif_netmask_string[256];
static char bif_addr_string[256];
static char bif_netmask_string[256];

#define ORIG_TABLES "/tmp/saved.tbl"


void gateway_tap_cleanup(int a)
{
  sigset_t sigset;
  sigset_t oldset;
  sigfillset(&sigset);
  sigprocmask(SIG_BLOCK,&sigset,&oldset);

  execute_command("ifconfig aif down");
  execute_command("brctl delif aif %s", gw_ifs.a.tap_name);


  if (!(gw_ifs.a.tap_no_phy)) {
    execute_command ("brctl delif aif %s", gw_ifs.a.name);
  }
  execute_command ("brctl delbr aif");
  execute_command ("ifconfig bif down");
  execute_command ("brctl delif bif %s", gw_ifs.b.tap_name);

  if (!(gw_ifs.b.tap_no_phy)) {
    execute_command ("brctl delif bif %s", gw_ifs.b.name);
  }
  execute_command ("brctl delbr bif");

  if ((gw_ifs.c_tap_remote_access == 1) && (a == 1))  {
    if (!(gw_ifs.a.tap_no_phy)) {
      execute_command ("ifconfig %s %s netmask %s", gw_ifs.a.name, aif_addr_string, aif_netmask_string);
    }
    if (!(gw_ifs.b.tap_no_phy)) {
      execute_command ("ifconfig %s %s netmask %s", gw_ifs.b.name, bif_addr_string, bif_netmask_string);
    }
  }
  sigprocmask(SIG_SETMASK,&oldset,0);
}



static int gateway_get_address(const char *ifname, struct sockaddr_in *saddr)
{
  struct ifreq if_str;
  int fd = socket (PF_INET, SOCK_DGRAM, 0);
  if (fd < 0)
    return -1;
  
  memset (&if_str, 0, sizeof (struct ifreq));
  strcpy (if_str.ifr_name, ifname);
  int ret = ioctl (fd, SIOCGIFADDR, &if_str);
  if (ret == 0) 
    memcpy (saddr, &if_str.ifr_addr, sizeof (struct sockaddr));
  close(fd);
  return ret;
}

static int gateway_get_netmask(const char *ifname, struct sockaddr_in *saddr)
{
  struct ifreq if_str;
  int fd = socket (PF_INET, SOCK_DGRAM, 0);
  if (fd < 0)
    return -1;
  
  memset (&if_str, 0, sizeof (struct ifreq));
  strcpy (if_str.ifr_name, ifname);
  int ret = ioctl (fd, SIOCGIFNETMASK, &if_str);
  if (ret == 0) 
    memcpy (saddr, &if_str.ifr_addr, sizeof (struct sockaddr));
  close(fd);
  return ret;
}


void gateway_tap_rules (void)
{
  int ret;
  struct sockaddr_in saddr;
  gateway_tap_cleanup (0);

  if (gw_ifs.c_tap_remote_access == 1) {
    if (!(gw_ifs.a.tap_no_phy)) {
      ret = gateway_get_address(gw_ifs.a.name, &saddr);
      if (ret == 0)
        strcpy (aif_addr_string, inet_ntoa (saddr.sin_addr));

      LOG ("gwio %s address %s with res %d\n", gw_ifs.a.name, aif_addr_string, ret);
      
      ret = gateway_get_netmask(gw_ifs.a.name, &saddr);
      if (ret == 0)
        strcpy (aif_netmask_string, inet_ntoa (saddr.sin_addr));
      LOG ("gwio %s netmask %s with result %d\n", gw_ifs.a.name, aif_netmask_string, ret);
    }

    if (!(gw_ifs.b.tap_no_phy)) {
      ret = gateway_get_address(gw_ifs.b.name, &saddr);
      if (ret == 0)
        strcpy (bif_addr_string, inet_ntoa (saddr.sin_addr));

      LOG ("gwio %s address %s with result %d\n", gw_ifs.b.name, bif_addr_string, ret);
      
      ret = gateway_get_netmask(gw_ifs.b.name, &saddr);
      if (ret == 0)
        strcpy (bif_netmask_string, inet_ntoa (saddr.sin_addr));
      LOG ("gwio %s address %s with result %d\n", gw_ifs.b.name, bif_netmask_string, ret);
    }
  }
  execute_command ("ip link set dev %s up", gw_ifs.a.tap_name);
  execute_command ("ip link set dev %s up", gw_ifs.b.tap_name);
  execute_command ("brctl addbr aif");
  execute_command ("brctl addif aif %s", gw_ifs.a.tap_name);

  if (!(gw_ifs.a.tap_no_phy)) {
    execute_command ("brctl addif aif %s", gw_ifs.a.name);
  }

  execute_command ("brctl stp aif off");
  execute_command ("ifconfig aif up");
  execute_command ("brctl addbr bif");
  execute_command ("brctl addif bif %s", gw_ifs.b.tap_name);

  if (!(gw_ifs.b.tap_no_phy)) {
    execute_command ("brctl addif bif %s", gw_ifs.b.name);
  }
  execute_command ("brctl stp bif off");
  execute_command ("ifconfig bif up");
  if (gw_ifs.c_tap_remote_access == 1) {
    if (!(gw_ifs.a.tap_no_phy)) {
      execute_command ("ip addr del %s dev %s", aif_addr_string, gw_ifs.a.name);
      execute_command ("ifconfig %s %s netmask %s", "aif", aif_addr_string, aif_netmask_string);
    }
    if (!(gw_ifs.a.tap_no_phy)) {
      execute_command ("ip addr del %s dev %s", bif_addr_string, gw_ifs.b.name);
      execute_command ("ifconfig %s %s netmask %s", "bif", bif_addr_string, bif_netmask_string);
    }
  }
}

